package com.example.xinlijiankangsys.service;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.example.xinlijiankangsys.pojo.WebSocketRequestData;
import com.example.xinlijiankangsys.pojo.WebSocketRequestDataMateResult;
import com.example.xinlijiankangsys.pojo.WebSocketResponseData;
import com.example.xinlijiankangsys.util.DataProcessingUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


@Service
public class WebSocketService {
    private static final org.slf4j.Logger log
            = org.slf4j.LoggerFactory.getLogger(WebSocketService.class);

    @Autowired
    private UserService userService;

    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private RedisService redisService;
    /**
     * 处理接收到的消息负载，解析数据并进行相应的处理。
     *
     * @param currentId 当前用户的 用户 id。
     * @param msgLoad        接收到的消息负载，包含待处理的数据。
     * @param session        当前用户的 WebSocket 会话，用于发送响应。
     * @param clientMap      存储在线用户的 WebSocket 会话的映射。
     */
    public void processMessage(String currentId, String msgLoad, WebSocketSession session, ConcurrentHashMap<String, WebSocketSession> clientMap) {
        // 1. 解析数据格式
        WebSocketRequestData requestData = DataProcessingUtil.processingRequestData(msgLoad);
        log.info("接受的消息解析为:{}" ,requestData);

        // 2. 数据格式解析成功
        if (requestData.getIsOkDataProcessing()) {
            // 定义的规则
            String rule = requestData.getJsonMsg();

            // 3. 解析数据
            WebSocketRequestDataMateResult requestDataMateResult = DataProcessingUtil.getRequestDataMateResult(requestData.getJsonData(), rule);
            log.info("接受的数据 {} {}",requestDataMateResult,requestDataMateResult.isValid());
            // 4. 数据解析成功
            if (requestDataMateResult.isValid()) {
                // 获取数据
                Map<String, String> mapData = requestDataMateResult.getMapData();
                if("SEND_MSG".equals(rule)){
                    //获取"receiver"
                    String receiver= mapData.get("receiver");
                    //  检查并处理anonymous_前缀
                    if (receiver != null && receiver.startsWith("anonymous_")) {
                        // 移除前缀（保留原始ID部分）
                        String cleanReceiver = receiver.substring("anonymous_".length());
                        mapData.put("originalReceiver", receiver); // 保留原始值
                        // 验证剩余部分是否合法（示例：只允许数字）
                        mapData.put("receiver", cleanReceiver);    // 使用处理后值
                    }
                }
                // 检验是否是有效数据
                if (checkMapData(currentId, mapData, rule)) {
                    // 处理数据
                    handleMapData(mapData, session,clientMap,rule);
                    return; // 处理完成，退出方法
                }
            }
        }
        // 如果数据格式解析失败或数据无效，回应错误响应
        sendRespMsg(session, "msg_error", 0, "");
    }
    /**
     * 校验 map 数据的有效性，根据不同的规则进行检查。
     *
     * @param userId  当前用户的  标识符。
     * @param mapData  待校验的数据映射，包含请求者信息和其他相关数据。
     * @param rule     校验规则，用于决定校验的逻辑。
     * @return 如果数据有效返回 true，否则返回 false。
     */
    private Boolean checkMapData(String userId, Map<String, String> mapData, String rule) {
        // 校验规则：SEND_MSG   ANONYMOUS_MSG
        if ("SEND_MSG".equals(rule) ||"ANONYMOUS_MSG".equals(rule)) {
            String sender = mapData.get("sender");
            String receiver = mapData.get("receiver");
            String requestTime = mapData.get("timestamp");
            String msg = mapData.get("content");
            log.info("时间异常:{} {}",requestTime,isValidDate(requestTime));
            // 检查消息内容、请求者id、请求时间是否有效，以及请求者和被请求者是否不同
            return msg!= null && !msg.trim().isEmpty()
                    && userId.equals(sender)
                    && isValidDate(requestTime)
                    && !userId.equals(receiver)
                    && userService.isUserExist(receiver)
                    ;
        }
        // 如果不符合任何规则，返回 false
        return false;
    }
    /**
     * 处理来自 WebSocket 的映射数据，根据不同的规则调用相应的处理方法
     *
     * @param mapData    包含请求数据的映射
     * @param session    当前 WebSocket 会话
     * @param clientMap  存储在线用户的会话
     * @param rule       处理的规则类型
     */
    private void handleMapData(Map<String, String> mapData, WebSocketSession session,ConcurrentHashMap<String, WebSocketSession> clientMap, String rule) {
        if ("SEND_MSG".equals(rule)){
            sendMessage(session,mapData,clientMap,false,rule);
        }

        if("ANONYMOUS_MSG".equals(rule)){
            sendMessage(session,mapData,clientMap,true,rule);
        }
    }




    /**
     * 处理发送消息的请求
     *
     * @param session 当前 WebSocket 会话
     * @param mapData 包含请求者和被请求者信息的映射
     * @param clientMap 存储在线用户的会话
     */
    private void sendMessage(WebSocketSession session, Map<String, String> mapData, ConcurrentHashMap<String, WebSocketSession> clientMap,boolean isAnonymous,String rule) {
        // 从 mapData 中提取请求者和被请求者的邮箱及消息内容
        String sender = mapData.get("sender");
        String receiver = mapData.get("receiver");
        String tepId = mapData.get("tempId");
        // 如果不是匿名  获取用户姓名和用户头像路径
        Map<String, String> resultMap = new HashMap<>(mapData); // Create a new copy
        String username=null;
        if(!isAnonymous) {
            Map<String,Object> userInfoMap=userInfoService.getUserInfoAsMap(sender);
            if (userInfoMap!=null&& userInfoMap.get("name")!=null) {
                resultMap.put("name", String.valueOf(userInfoMap.get("name")));
            }else{
                resultMap.put("name", "默认");
            }
            if (userInfoMap!=null&& userInfoMap.get("auth")!=null) {
                resultMap.put("auth", String.valueOf(userInfoMap.get("auth")));
            }else{
                resultMap.put("auth", "1");
            }
            if (userInfoMap!=null&& userInfoMap.get("avatar_path")!=null) {
                resultMap.put("avatar_path",String.valueOf(userInfoMap.get("avatar_path")));
            }else{
                resultMap.put("avatar_path", "/avatars/default.png");
            }
        }
        //如果 接受者在线 直接推送即可
        // 发送消息给接收者
        List<Map<String, String>> list = new ArrayList<>();
        list.add(resultMap);  // 列表现在包含一个元素（即mapData整个Map）
        boolean sendOk = sendMsgIfUserOnline(receiver, rule, clientMap,list);
        log.info("发送者名字: {},sender:{},receiver:{} sendOk:{}",username,sender,receiver,sendOk );
        if (!sendOk) {
            try {
                // 如果接收者不在线，缓存消息数据  存放可以辨识匿名和非匿名的数据
                mapData.put("sign",String.valueOf(isAnonymous));
                redisRequestedData("websocketMsgBox", receiver,mapData);
            }catch (Exception e){
                // 如果数据格式解析失败或数据无效，回应错误响应
                sendRespMsg(session, "msg_error", 0, "");
            }
        }
        // 存储成功，发送成功响应给请求者
        Map<String,String> stringMap=new HashMap<>();
        //匿名
        if(mapData.get("originalReceiver")!=null){
            stringMap.put("receiver",mapData.get("originalReceiver"));
        }else{
            stringMap.put("receiver",mapData.get("receiver"));
        }
        stringMap.put("tempId",tepId);
        stringMap.put("sign",rule);
        sendRespMsg(session, "send_msg_ok", 1, stringMap);
    }

    /**
     * 将待缓存的数据存储到 Redis 中，支持过期时间管理
     *
     * @param <T>           要缓存的数据的类型
     * @param prefix        Redis 键的前缀
     * @param sign 请求者的邮箱，用于生成唯一的 Redis 键
     * @param value         要缓存的数据对象
     */
    private  <T> void redisRequestedData(String prefix, String sign, T value) {
        // 生成 Redis 键
        String key = prefix + sign;

        // 从 Redis 中获取当前键的值
        String json = (String) redisService.getValue(key);
        List<T> list;
        log.info("jsom：{}",json);
        // 如果 Redis 中没有数据
        if (json == null) {
            // 创建新的列表并添加 value
            list = new ArrayList<>();
            list.add(value); // 直接添加对象
        } else {
            // 如果已有数据，解析为 List<T>
            list = JSON.parseObject(json, new TypeReference<List<T>>() {});
            assert list != null; // 确保列表不为空
            list.add(value); // 添加新的数据
        }
        // 存储不具有过期时间的数据
        redisService.setValue(key, list);
    }

    public void getMsgFromBox(String userId,ConcurrentHashMap<String, WebSocketSession> clientMap){
        String key="websocketMsgBox"+userId;
        String json = (String) redisService.getValue(key);
        if(json==null) return;
        List<Map<String,String>>  mapList= JSON.parseObject(json, new TypeReference<List<Map<String,String>>>() {});
        // 发送消息给接收者
        List<Map<String, String>> list = new ArrayList<>();
        //遍历mapList
        // 方式2：Java8 forEach遍历
        mapList.forEach(map -> {
            System.out.println("当前数据：" + map);
            String sender = map.get("sender");
            boolean isAnonymous=Boolean.parseBoolean(map.get("sign"));
            // 如果不是匿名  获取用户姓名和用户头像路径
            String username=null;
            if(!isAnonymous) {
                Map<String,Object> userInfoMap=userInfoService.getUserInfoAsMap(sender);
                if (userInfoMap!=null&& userInfoMap.get("name")!=null) {
                    map.put("name", String.valueOf(userInfoMap.get("name")));
                }else{
                    map.put("name", "默认");
                }
                if (userInfoMap!=null&& userInfoMap.get("auth")!=null) {
                    map.put("auth", String.valueOf(userInfoMap.get("auth")));
                }else{
                    map.put("auth", "1");
                }
                if (userInfoMap!=null&& userInfoMap.get("avatar_path")!=null) {
                    map.put("avatar_path",String.valueOf(userInfoMap.get("avatar_path")));
                }else{
                    map.put("avatar_path", "/avatars/default.png");
                }

            }
            list.add(map);  // 列表现在包含一个元素（即mapData整个Map）
        });


       if(sendMsgIfUserOnline(userId, "MSG", clientMap,list)){
           try {
               redisService.deleteValue(key);
           }catch (Exception e){
               log.error("请删除 redis键{}",key);
           }
       }
    }
    /**
     * 检查指定用户是否在线，如果在线则通过 WebSocket 发送消息。
     *
     * @param userTo 目标用户的标识（如用户名或用户ID）。
     * @param respKey 响应消息的文本内容，用于传达信息。
     * @param clientMap 存储用户 WebSocket 会话的并发哈希映射，用于查找用户在线状态。
     * @param value 需要发送的附加数据，可以是任意对象。
     * @return 如果用户在线并成功发送消息，则返回 true；否则返回 false。
     */
    private boolean sendMsgIfUserOnline(String userTo, String respKey, ConcurrentHashMap<String, WebSocketSession> clientMap, Object value) {
        // 从客户端映射中获取指定用户的 WebSocket 会话
        WebSocketSession session = clientMap.get(userTo);
        // 检查用户是否在线（即会话是否存在）
        if (session != null) {
            // 用户在线，发送响应消息
            sendRespMsg(session, respKey, 1, value);
            return true; // 返回 true，表示消息发送成功
        }

        // 用户不在线，返回 false
        return false;
    }
    /**
     * 通过 WebSocket 会话发送响应消息。
     *
     * @param session 当前的 WebSocket 会话，用于发送消息。
     * @param msg 响应消息的文本内容。
     * @param code 响应的状态码，通常用于表示操作的结果。
     * @param value 需要返回的附加数据，可以是任意对象。
     */
    private void sendRespMsg(WebSocketSession session, String msg, int code, Object value) {
        try {
            // 创建 Data 对象用于封装响应数据
            WebSocketResponseData data = new WebSocketResponseData();
            data.setCode(code); // 设置状态码
            data.setMsg(msg); // 设置响应消息
            data.setData(JSON.toJSONString(value)); // 将附加数据转换为 JSON 字符串
            // 发送消息到客户端
            session.sendMessage(new TextMessage(JSON.toJSONString(data)));
        } catch (IOException e) {
            // 发送消息过程中出现异常，抛出运行时异常
            throw new RuntimeException(e);
        }
    }


    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public  boolean isValidDate(String dateStr) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
        try {
            LocalDateTime parsedDate = LocalDateTime.parse(dateStr, formatter); // 尝试解析字符串
            // 检查解析后的日期是否小于等于当前时间
            return !parsedDate.isAfter(LocalDateTime.now());
        } catch (DateTimeParseException e) {
            return false; // 如果解析失败，返回 false
        }
    }

}
